﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Reflection;

namespace GingerBeard.IDL
{
	public partial class IDLVariable
	{
		public override bool GeneratePre_CPlusPlus(CompileSettings settings)
		{
			String varType = Type;
			String varName = Name;

			if (varType.ToLower().Contains("array"))
			{
				int firstBracket = varType.IndexOf('[');
				int lastBracket = varType.IndexOf(']');
				String arrayType = varType.Substring(firstBracket + 1, lastBracket - firstBracket - 1);
				int arrayCount = 1;
				varType = varType.Substring(lastBracket + 1);

				if (varType.Contains("["))
				{
					firstBracket = varType.IndexOf('[');
					lastBracket = varType.IndexOf(']');
					String countString = varType.Substring(firstBracket + 1, lastBracket - firstBracket - 1);

					if (!int.TryParse(countString, out arrayCount))
					{
						throw new Exception("Invalid characters found in array count specifier");
					}

					varType = arrayType;
				}
				else
				{
					varType = "Link<" + arrayType + ">";
				}

				if (arrayCount > 1)
					varName = varName + "[" + arrayCount + "]";
			}
			else if (varType.ToLower().Contains("link"))
			{
				int firstBracket = varType.IndexOf('[');
				int lastBracket = varType.IndexOf(']');
				String linkType = varType.Substring(firstBracket + 1, lastBracket - firstBracket - 1);
				varType = "Link<"+linkType+">";
			}

			settings.OutputWriter.WriteLine(settings.IndentString + varType + " " + varName + ";");
			return true;
		}

		public override void GeneratePost_CPlusPlus(CompileSettings settings)
		{

		}
	}
	public partial class IDLObject
	{
		public override bool GeneratePre_CPlusPlus(CompileSettings settings)
		{
			settings.OutputWriter.WriteLine(settings.IndentString + "struct " + Name);
			settings.OutputWriter.WriteLine(settings.IndentString + "{");
			return true;
		}

		public override void GeneratePost_CPlusPlus(CompileSettings settings)
		{
			settings.Indent++;
			if (settings.CodeGenLoading != CodeGeneration.Off)
			{
				GenerateLoadingCode_CPlusPlus(settings);
			}

			if (settings.CodeGenSaving != CodeGeneration.Off)
			{
				GenerateSaving_CPlusPlus(settings);
			}
			settings.Indent--;

			settings.OutputWriter.WriteLine(settings.IndentString + "};");
		}

		private void GenerateSaving_CPlusPlus(CompileSettings settings)
		{
			settings.OutputWriter.WriteLine(settings.IndentString + "void Serialise(std::ostream& writer)");
			settings.OutputWriter.WriteLine(settings.IndentString + "{");
			List<IDLVariable> variables = FindNodes<IDLVariable>();
			foreach (IDLVariable var in variables)
			{
				if (var.Type.Contains("Array["))
				{

				}
				else if (var.Type.Contains("Link["))
				{

				}
				else
				{
					settings.OutputWriter.WriteLine(settings.IndentString + "\twriter << " + var.Name + ";");
				}
			}
			settings.OutputWriter.WriteLine(settings.IndentString + "}");
		}

		private void GenerateLoadingCode_CPlusPlus(CompileSettings settings)
		{
			settings.OutputWriter.WriteLine(settings.IndentString + "void Deserialise(std::istream& reader)");
			settings.OutputWriter.WriteLine(settings.IndentString + "{");
			List<IDLVariable> variables = FindNodes<IDLVariable>();
			foreach (IDLVariable var in variables)
			{
				if (var.Type.Contains("Array["))
				{

				}
				else if (var.Type.Contains("Link["))
				{

				}
				else
				{
					//settings.OutputWriter.WriteLine(settings.IndentString + "\treader >> " + var.Name + ";");
				}
			}
			settings.OutputWriter.WriteLine(settings.IndentString + "}");
		}
	}
	public partial class IDLEnum
	{
		public override bool GeneratePre_CPlusPlus(CompileSettings settings)
		{
			settings.OutputWriter.WriteLine(settings.IndentString + "enum " + Name);
			settings.OutputWriter.WriteLine(settings.IndentString + "{");
			String[] values = Values.Split(',');
			foreach (String value in values)
			{
				settings.OutputWriter.WriteLine(settings.IndentString + "\t" + value + ",");
			}
			settings.OutputWriter.WriteLine(settings.IndentString + "};");
			return true;
		}

		public override void GeneratePost_CPlusPlus(CompileSettings settings)
		{

		}
	}
	public partial class IDLNamespace
	{
		public override bool GeneratePre_CPlusPlus(CompileSettings settings)
		{
			settings.OutputWriter.WriteLine(settings.IndentString + "namespace " + Name);
			settings.OutputWriter.WriteLine(settings.IndentString + "{");
			return true;
		}

		public override void GeneratePost_CPlusPlus(CompileSettings settings)
		{
			settings.OutputWriter.WriteLine(settings.IndentString + "}");
		}
	}
	public partial class IDLIfLanguage
	{
		public override bool GeneratePre_CPlusPlus(CompileSettings settings)
		{
			settings.Indent--;
			return Name.ToLower() == "cplusplus";
		}

		public override void GeneratePost_CPlusPlus(CompileSettings settings)
		{
			settings.Indent++;
		}
	}
	public partial class IDLTypes
	{
		public override bool GeneratePre_CPlusPlus(CompileSettings settings)
		{
			settings.Indent--;
			return true;
		}

		public override void GeneratePost_CPlusPlus(CompileSettings settings)
		{
			settings.Indent++;
		}
	}
	public partial class IDLType
	{
		public override bool GeneratePre_CPlusPlus(CompileSettings settings)
		{
			if (Name != ActualType)
				settings.OutputWriter.WriteLine(settings.IndentString + "typedef " + ActualType + " " + Name + ";");
			return true;
		}

		public override void GeneratePost_CPlusPlus(CompileSettings settings)
		{

		}
	}
	public partial class IDLContainer
	{
		public override bool GeneratePre_CPlusPlus(CompileSettings settings)
		{
			settings.OutputWriter.WriteLine(settings.IndentString + "struct " + Name);
			settings.OutputWriter.WriteLine(settings.IndentString + "{");
			settings.OutputWriter.WriteLine(settings.IndentString + "};");
			return false;
		}

		public override void GeneratePost_CPlusPlus(CompileSettings settings)
		{

		}
	}
	public partial class IDL
	{
		public override bool GeneratePre_CPlusPlus(CompileSettings settings)
		{
			String includeGuard =
				"INCLUDED_IDL_" + 
				SourceFilename.
				Replace(' ', '_').
				Replace('\\', '_').
				Replace('/', '_').
				Replace(':', '_').
				Replace('.', '_');
			includeGuard = includeGuard.ToUpper();

			settings.OutputWriter.WriteLine("// --------------------------------------------------------------------------------------------------");
			settings.OutputWriter.WriteLine("#ifndef " + includeGuard);
			settings.OutputWriter.WriteLine("#define " + includeGuard);
			settings.OutputWriter.WriteLine("// --------------------------------------------------------------------------------------------------");
			settings.OutputWriter.WriteLine("// BEGIN AUTOGENERATED CODE ");
			settings.OutputWriter.WriteLine("// --------------------------------------------------------------------------------------------------");
			settings.OutputWriter.WriteLine("// Assembly : " + Assembly.GetExecutingAssembly().ToString() );
			settings.OutputWriter.WriteLine("// Time     : " + DateTime.Now );
			settings.OutputWriter.WriteLine("// Source   : " + SourceFilename );
			settings.OutputWriter.WriteLine("// --------------------------------------------------------------------------------------------------");
			settings.OutputWriter.WriteLine("#include <iostream>");
			settings.OutputWriter.WriteLine("// --------------------------------------------------------------------------------------------------");
			settings.OutputWriter.WriteLine("namespace " + Name);
			settings.OutputWriter.WriteLine("{");
			settings.OutputWriter.WriteLine("\ttemplate <class T> struct Link { union { unsigned int offset; T* pObj; }; };");

			return true;
		}

		public override void GeneratePost_CPlusPlus(CompileSettings settings)
		{
			settings.OutputWriter.WriteLine("}");
			settings.OutputWriter.WriteLine("// --------------------------------------------------------------------------------------------------");
			settings.OutputWriter.WriteLine("#endif");
			settings.OutputWriter.WriteLine("// --------------------------------------------------------------------------------------------------");
			settings.OutputWriter.WriteLine("// END AUTOGENERATED CODE");
			settings.OutputWriter.WriteLine("// --------------------------------------------------------------------------------------------------");
		}
	}
}
